在測試時常會需要建立假資料以供測試使用,就可以安裝 FactoryBot 來建立資料
指令 gem "factory_bot_rails"
並且 bundle install
官方文件-FactoryBot Getting Started
基本語法就是使用 FactoryBot.create(:user)
就可以建立出一筆User了
可以在新增 spec/support/factory_bot.rb
並且把以下指令放在檔案內,在 rspec 時就可以省略FactoryBot
,直接 create(:user)
即可,那你也可以直接放在 rails_helper.rb
也同樣有效。
#spec/support/factory_bot.rb or rails_helper.rb
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
end
看文件只要將 file 依照以下位置擺放都會自動吃到
test/factories.rb
spec/factories.rb
test/factories/*.rb
spec/factories/*.rb
接下來新增一個 spec/factories/users.rb
# This will guess the User class
FactoryBot.define do
factory :user do
name { "CK" }
email { "ck@gmail.com" }
end
end
factory
會從 class 去搜尋是否有 User 這個 class,沒有的話他會提醒你他找不到,裡頭就可以直接填寫 model 欄位右方 block 裡面就是放內容。
我們到 console 試試是否能夠建立出來吧!
# rails console -e test
2.6.6 :001 > FactoryBot.create(:user)
D, [2021-09-09T19:06:57.193940 #42363] DEBUG -- : (1.7ms) SELECT sqlite_version(*)
D, [2021-09-09T19:06:57.230186 #42363] DEBUG -- : TRANSACTION (0.2ms) begin transaction
D, [2021-09-09T19:06:57.231393 #42363] DEBUG -- : User Exists? (0.6ms) SELECT 1 AS one FROM "users" WHERE "users"."name" = ? LIMIT ? [["name", "ck"], ["LIMIT", 1]]
D, [2021-09-09T19:06:57.234314 #42363] DEBUG -- : User Create (0.8ms) INSERT INTO "users" ("created_at", "updated_at", "name", "email") VALUES (?, ?, ?, ?) [["created_at", "2021-09-09 11:06:57.231907"], ["updated_at", "2021-09-09 11:06:57.231907"], ["name", "ck"], ["email", "ck@gmail.com"]]
D, [2021-09-09T19:06:57.235901 #42363] DEBUG -- : TRANSACTION (0.9ms) commit transaction
=> #<User id: 1, created_at: "2021-09-09 11:06:57.231907000 +0000", updated_at: "2021-09-09 11:06:57.231907000 +0000", name: "ck", email: "ck@gmail.com", phone: nil>
所以就可以把原本的測試改寫為
# user_spec.rb
require 'rails_helper'
RSpec.describe User, type: :model do
describe 'validations' do
it { is_expected.to validate_presence_of(:name) }
end
describe 'count user' do
let(:user) { create(:user) } # 此處使用factorybot 建立
it 'no user' do
expect(User.count).to eq(0)
end
it 'one user' do
user
expect(User.count).to eq(1)
end
end
end
但這邊會遇到一個問題,如果我想一次建立兩筆user但user名稱又不能重複?
如果使用目前的user建立出來兩筆資料 name 與 email 都會相同,該如何改呢?
# This will guess the User class
FactoryBot.define do
factory :user do
sequence(:name) { |n| "ck-#{n}"}
sequence(:email) { |n| "ck-#{n}@gmail.com" }
end
end
#rails console -e test
=> #<User id: 1, created_at: "2021-09-09 11:18:41.436395000 +0000", updated_at: "2021-09-09 11:18:41.436395000 +0000", name: "ck-1", email: "ck-1@gmail.com", phone: nil>
=> #<User id: 2, created_at: "2021-09-09 11:19:17.282845000 +0000", updated_at: "2021-09-09 11:19:17.282845000 +0000", name: "ck-2", email: "ck-2@gmail.com", phone: nil>
可以看到名稱多編號這樣一來就不會重複!
那你也可以使用 create_list(:factory_name,count)
一次建立兩筆
#rails console -e test
2.6.6 :003 > FactoryBot.create_list(:user,2)
=> [#<User id: 3, created_at: "2021-09-09 11:20:10.871562000 +0000", updated_at: "2021-09-09 11:20:10.871562000 +0000", name: "ck-3", email: "ck-3@gmail.com", phone: nil>,
#<User id: 4, created_at: "2021-09-09 11:20:10.877319000 +0000", updated_at: "2021-09-09 11:20:10.877319000 +0000", name: "ck-4", email: "ck-4@gmail.com", phone: nil>]
在 factory 後方一樣可以輸入 attribute,覆蓋掉原本預設的資料。
#rails console -e test
2.6.6 :005 > FactoryBot.create(:user, name:'ck_over',email: 'ck_over@gmailc.om')
=> #<User id: 5, created_at: "2021-09-09 11:22:43.618214000 +0000", updated_at: "2021-09-09 11:22:43.618214000 +0000", name: "ck_over", email: "ck_over@gmailc.om", phone: nil>
基本上使用這些就可以解決大部分建立資料的問題,明天我們就可以來講解,trait
、parent
、association
、alias
!